@node Generic dispatch system
@section Generic dispatch system

@cindex multimethod dispatch
@cindex type dispatch
@cindex generic functions
@cindex generic predicate dispatch
@stindex methods
@stindex meta-methods
Scheme48 supports a CLOS-style generic procedure dispatch system, based
on type predicates.  The main interface is exported by @code{methods}.
The internals of the system are exposed by the @code{meta-methods}
structure, but they are not documented here.  The generic dispatch
system is used in Scheme48's @embedref{Writer, writer} and numeric
system.
@c @embedref{numeric system, Numeric system}.

@dfn{Types} in Scheme48's generic dispatch system are represented using
type predicates, rather than having every object have a single,
well-defined `class.'  The naming convention for simple types is to
prefix the type name with a colon.  The types support multiple
inheritance.  Method specificity is determined based on descending
order of argument importance.  That is, given two methods, @var{M} &
@var{N}, such that they are both applicable to a given sequence of
arguments, and an index @var{i} into that sequence, such that @var{i}
is the first index in @var{M}'s & @var{N}'s lists of argument type
specifiers, from left to right, where the type differs: if the type for
@var{M}'s argument at @var{i} is more specific than the corresponding
type in @var{N}'s specifiers, @var{M} is considered to be more specific
than @var{N}, even if the remaining argument type specifiers in @var{N}
are more specific.

@deffn syntax define-simple-type name (supertype @dots{}) predicate
Defines @var{name} to be a @dfn{simple type} with the given predicate
and the given supertypes.
@end deffn

@deffn procedure singleton value @returns{} simple-type
Creates a @dfn{singleton type} that matches only @var{value}.
@end deffn

@deffn syntax define-generic proc-name method-table-name [prototype]
Defines @var{proc-name} to be a @dfn{generic procedure} that, when
invoked, will dispatch on its arguments via the @dfn{method table} that
@var{method-table-name} is defined to be and apply the most specific
method it can determine defined in the @var{method-table-name} method
table to its arguments.  The convention for naming variables that will
be bound to method tables is to add an ampersand to the front of the
name.  @var{Prototype} is a suggestion for what method prototypes
should follow the shape of, but it is currently ignored.
@end deffn

@deffn syntax define-method method-table prototype body
Adds a @dfn{method} to @var{method-table}, which is usually one defined
by @code{define-generic}.@footnote{There is an internal interface, a
sort of meta-object protocol, to the method dispatch system, but it is
not yet documented.}  @var{Prototype} should be a list whose elements
may be either identifiers, in which case that parameter is not used for
dispatching, or lists of two elements, the @code{car} of which is the
parameter name and the @code{cadr} of which should evaluate to the type
on which to dispatch.  As in many generic dispatch systems of similar
designs, methods may invoke the next-most-specific method.  By default,
the name @code{next-method} is bound in @var{body} to a nullary
procedure that calls the next-most-specific method.  The name of this
procedure may be specified by the user by putting the sequence
@code{"next" @var{next-method-name}} in @var{prototype}, in which case
it will be @var{next-method-name} that is bound to that procedure.  For
example:

@lisp
(define-method &frob ((foo :bar) "next" frobozz)
  (if (mumble? foo)
      (frobozz)     ; Invoke the next method.
      (yargh blargle foo)))@end lisp
@end deffn

A number of simple types are already defined & exported by the
@code{methods} structure.  Entries are listed as @code{@var{type-name}
<- (@var{supertype} @dots{}), @var{predicate}}

@itemize
@item @code{:values <- (), (lambda (x) #t)} --- Abstract supertype of
all run-time values

@item @code{:value <- (:values), (lambda (x) #t)} --- Abstract
supertype of all first-class values

@item @code{:zero <- (:values), (lambda (x) #f)} --- Type that no
objects satisfy

@item @code{:number <- (:value), number?}

@item @code{:complex <- (:number), complex?} --- (This happens to be
equivalent to @code{:number}.)

@item @code{:real <- (:complex), real?}

@item @code{:rational <- (:real), rational?}

@item @code{:integer <- (:rational), integer?}

@item @code{:exact-integer <- (:integer),
(lambda (x) (and (integer? x) (exact? x)))}

@item @code{:boolean <- (:value), boolean?}

@item @code{:symbol <- (:value), symbol?}

@item @code{:char <- (:value), char?}

@item @code{:null <- (:value), null?}

@item @code{:pair <- (:value), pair?}

@item @code{:vector <- (:value), vector?}

@item @code{:string <- (:value), string?}

@item @code{:procedure <- (:value), procedure?}

@item @code{:input-port <- (:value), input-port?}

@item @code{:output-port <- (:value), output-port?}

@item @code{:eof-object <- (:value), eof-object?}

@item @code{:record <- (:value), record?}
@end itemize
